/*
 * jabberd - Jabber Open Source Server
 * Copyright (c) 2002-2003 Jeremie Miller, Thomas Muldowney,
 *                         Ryan Eatmon, Robert Norris
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
 */

 /**
  * Antti Leppä / Foyt 2010
  *
  * Authreg method for Jabberd2 that authenticates users via JSON requests.
  *
  * Following options need to be configured in c2s.xml in order to use this method.
  *
  * <json>
  *   <host>www.myhost.com</host>
  *   <port>80</port>
  *   <path>/some/path/to/auth.json</path>
  *   <encrypt>none/ssl</encrypt>
  *   <authentication>none/secret/basicauth/digestauth</authentication>
  *   <!-- secret needs to be defined if authentication is set to secret-->
  *   <secret>mysecret</secret>
  *   <!-- username and password fields need to be defined if authentication is set either to basicauth or digestauth -->
  *   <username>username</username>
  *   <password>password</password>
  * </json>
  *
  * Server should return JSON string containing "statusCode": 0 when authentication succeeds and "statusCode": 1 when it does not
  *
  * This requires libjson0 to be installed.
  */

  /**
   * !!! This is code is still in highly experimental stage !!!
   */

#include "c2s.h"
#include "json_request.h"

#include <json/json.h>

typedef struct jsoncontext_st {
  char *url;
  char *authentication;
  char *encrypt;
  char *secret;
  char *username;
  char *password;
} *jsoncontext_t;

static int _ar_json_user_exists(authreg_t ar, char *username, char *realm) {
  jsoncontext_t ctx = (jsoncontext_t) ar->private;

  char *params_template;
  int params_len;
  char *params;
  struct json_response_t json_response;

  params_template = "type=userexists&username=%s&realm=%s&secret=%s";
  params_len = strlen(params_template) + strlen(username) + strlen(realm) + strlen(ctx->secret);
  params = malloc(params_len * sizeof(char));
  sprintf(params, params_template, username, realm, ctx->secret);

  json_response = json_http_request(ctx->url, params);
  free(params);

  if (json_response.status != 0) {
	log_write(ar->c2s->log, LOG_ERR, "JSON authreg: user exists check failed with JSON error: %d", json_response.status);
	free_json_response(json_response);
	return 1;
  }

  free_json_response(json_response);
  return 0;
}

static int _ar_json_check_password(authreg_t ar, char *username, char *realm, char password[257]) {
  jsoncontext_t ctx = (jsoncontext_t) ar->private;

  char *params_template;
  int params_len;
  char *params;
  struct json_response_t json_response;

  params_template = "type=checkpassword&username=%s&password=%s&realm=%s&secret=%s";
  params_len = strlen(params_template) + strlen(username) + strlen(password) + strlen(realm) + strlen(ctx->secret);
  params = malloc(params_len * sizeof(char));
  sprintf(params, params_template, username, password, realm, ctx->secret);

  json_response = json_http_request(ctx->url, params);
  free(params);

  if (json_response.status != 0) {
	log_write(ar->c2s->log, LOG_ERR, "JSON authreg: check password failed with JSON error: %u", json_response.status);
	free_json_response(json_response);
    return 1;
  }

  free_json_response(json_response);
  return 0;
}

static int _ar_json_set_password(authreg_t ar, char *username, char *realm, char password[257]) {
  jsoncontext_t ctx = (jsoncontext_t) ar->private;

  return 0;
}

static int _ar_json_create_user(authreg_t ar, char *username, char *realm) {
  jsoncontext_t ctx = (jsoncontext_t) ar->private;

  return 0;
}

static int _ar_json_delete_user(authreg_t ar, char *username, char *realm) {
  jsoncontext_t ctx = (jsoncontext_t) ar->private;

  return 0;
}


static void _ar_json_free(authreg_t ar) {
  jsoncontext_t ctx = (jsoncontext_t) ar->private;

  json_deinitialize();

  free(ctx);
}

DLLEXPORT int ar_init(authreg_t ar) {
  char *host;
  char *port;
  char *path;
  char *authentication;
  char *encrypt;
  char *secret;
  char *username;
  char *password;

  host = config_get_one(ar->c2s->config, "authreg.json.host", 0);
  if (host == NULL) {
    log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no host specified in config file");
    return 1;
  }

  port = config_get_one(ar->c2s->config, "authreg.json.port", 0);
  if (host == NULL) {
    log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no port specified in config file");
    return 1;
  }

  path = config_get_one(ar->c2s->config, "authreg.json.path", 0);
  if (host == NULL) {
    log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no path specified in config file");
    return 1;
  }

  encrypt = config_get_one(ar->c2s->config, "authreg.json.encrypt", 0);
  if (encrypt == NULL) {
	log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no encrypt specified in config file");
    return 1;
  }

  if (strcmp(encrypt, "none") == 0) {

  } else if (strcmp(encrypt, "ssl") == 0) {
    log_write(ar->c2s->log, LOG_ERR, "JSON authreg: ssl encrytion is not implemented yet");
    return 1;
  } else {
    log_write(ar->c2s->log, LOG_ERR, "JSON authreg: unknown encryption specified: %s", encrypt);
    return 1;
  }

  authentication = config_get_one(ar->c2s->config, "authreg.json.authentication", 0);

  if (strcmp(authentication, "none") == 0) {

  } else if (strcmp(authentication, "secret") == 0) {
	secret = config_get_one(ar->c2s->config, "authreg.json.secret", 0);
	if (secret == NULL) {
	log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no secret specified in config file.");
	return 1;
	}
  } else if (strcmp(authentication, "basicauth") == 0) {
	log_write(ar->c2s->log, LOG_ERR, "JSON authreg: authentication %s is not implemented yet", authentication);
	return 1;

	username = config_get_one(ar->c2s->config, "authreg.json.username", 0);
	if (username == NULL) {
	  log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no username specified in config file.");
	  return 1;
	}

	password = config_get_one(ar->c2s->config, "authreg.json.password", 0);
	if (password == NULL) {
	  log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no password specified in config file.");
      return 1;
	}
  } else if (strcmp(authentication, "digestauth") == 0) {
	log_write(ar->c2s->log, LOG_ERR, "JSON Storage: authentication %s is not implemented yet", authentication);
	return 1;

	username = config_get_one(ar->c2s->config, "authreg.json.username", 0);
	if (username == NULL) {
	  log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no username specified in config file.");
	  return 1;
	}

	password = config_get_one(ar->c2s->config, "authreg.json.password", 0);
	if (password == NULL) {
	  log_write(ar->c2s->log, LOG_ERR, "JSON authreg: no password specified in config file.");
	  return 1;
	}
  } else {
	log_write(ar->c2s->log, LOG_ERR, "JSON authreg: unknown authentication mode (%s) specified in config file", authentication);
	return 1;
  }

  jsoncontext_t jsoncontext;
  jsoncontext = (jsoncontext_t) malloc( sizeof( struct jsoncontext_st ) );

  jsoncontext->url = get_url("http", host, port, path);
  jsoncontext->authentication = authentication;
  jsoncontext->encrypt = encrypt;
  jsoncontext->secret = secret;
  jsoncontext->username = username;
  jsoncontext->password = password;

  ar->private = jsoncontext;
  ar->free = _ar_json_free;
  ar->user_exists = _ar_json_user_exists;
  //ar->get_password = NULL;
  ar->check_password = _ar_json_check_password;
  //ar->set_password = _ar_json_set_password;
  //ar->create_user = _ar_json_create_user;
  // ar->delete_user = _ar_json_delete_user;

  json_initialize();

  log_write(ar->c2s->log, LOG_NOTICE, "JSON authreg: initialized");

  return 0;
}
